package com.morninz.ninepinview.widget;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.regex.Pattern;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.morninz.ninepinview.R;

public class PasscodeView extends View {
	private final static String TAG = "NinePINView";

	public static final int TYPE_1 = 1;
	public static final int TYPE_2 = 2;

	protected int colors[];
	ArrayList<Integer> colorlist;

	public static final int POINT_TYPE_BACK = 10;
	public static final int POINT_TYPE_DELETE = 11;
	protected final int POINT_COUNT = 12;
	protected final int DEFAULT_PADDING = 40;
	protected final int DEFAULT_POINT_COLOR = 0xFFFFFFFF;
	protected final int DEFAULT_CIRCLE_COLOR = 0xFF66CC99;
	protected final int DEFAULT_LINE_COLOR = 0x77FFFFFF;
	protected final int DEFAULT_WRONG_COLOR = 0xFFFF0000;

	private Paint mTextPaint;
	private Paint mTextFocusPaint;
	private float mPaddingPoint;
	private int mPaddingView;

	private int mPointColor;
	private float mPointSize;
	private Paint mPointPaint;

	private ArrayList<Paint> mCirclePaints;
	private int mCircleColor;
	private float mCircleWidth;
	private float mCircleRadius;
	private float mCircleRadiusKiss;
	private Paint mCirclePaint;

	private int mLineColor;
	private float mLineWidth;
	private Paint mLinePaint;

	private int mWrongColor;
	private Path[] mWrongPaths = new Path[POINT_COUNT];
	private Paint mWrongPaint;

	private boolean isWait;

	private Bitmap bmpBack, bmpDelete;

	private int type;
	/**
	 * The correct PIN.
	 */
	private String mCorrectPIN = "00";
	/**
	 * PIN is consist of points in the drawn shape.
	 */
	private String mDrawnPIN;

	/**
	 * 9 center points
	 */
	private Point[] mCenterPoints = new Point[POINT_COUNT];

	/**
	 * The all point have been drawn since last MotionEvent.ACTION_DOWN event
	 * triggered.
	 */
	private List<Point> mDrawnPoints = new ArrayList<Point>();

	/**
	 * The last been drawn point.
	 */
	private Point mLastDrawnPoint = null;

	private Pointer mPointer = null;

	private class Point {
		int index;// index of 9 center points
		float x;
		float y;
		float sizeRadius;
		boolean focus;
		boolean touch;
		boolean drawInc;
		boolean inc;

		@Override
		public String toString() {
			return "Point [index=" + index + ", x=" + x + ", y=" + y + "]";
		}
	}

	private class Pointer {
		int idPointer;
		int indexFocus;// index of 9 center points

		public Pointer(int idPointer, int indexFocus) {
			super();
			this.idPointer = idPointer;
			this.indexFocus = indexFocus;
		}

	}

	private int drawWidth;
	private int drawHeight;

	/**
	 * The current X coordinate of finger
	 */
	private float mCurrX;
	/**
	 * The current Y coordinate of finger
	 */
	private float mCurrY;

	protected boolean mWillDrawWrongTriangle;

	protected OnDrawListener mOnDrawListener;

	protected Mode mCurrMode = Mode.MODE_WORK;

	public static enum Mode {
		/**
		 * Study correct PIN shape mode.
		 */
		MODE_STUDY,

		/**
		 * Inspect drawn PIN shape mode.
		 */
		MODE_WORK
	}

	public PasscodeView(Context context) {
		this(context, null);
	}

	public PasscodeView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public PasscodeView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);

		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.NinePINView);

		mPointColor = a.getColor(R.styleable.NinePINView_pointColor,
				DEFAULT_POINT_COLOR);
		mCircleColor = a.getColor(R.styleable.NinePINView_circleColor,
				DEFAULT_CIRCLE_COLOR);
		mLineColor = a.getColor(R.styleable.NinePINView_lineColor,
				DEFAULT_LINE_COLOR);
		mWrongColor = a.getColor(R.styleable.NinePINView_wrongColor,
				DEFAULT_WRONG_COLOR);

		mPointSize = a.getDimension(R.styleable.NinePINView_circleRadius, 8.0f);
		mCircleWidth = a
				.getDimension(R.styleable.NinePINView_circleWidth, 5.0f);
		mLineWidth = a.getDimension(R.styleable.NinePINView_lineWidth, 5.0f);
		// mCircleRadius = a.getDimension(R.styleable.NinePINView_circleRadius,
		// 40.0f);

		mPaddingView = (int) a.getDimension(
				R.styleable.NinePINView_paddingSize, DEFAULT_PADDING);

		a.recycle();

		bmpBack = BitmapFactory.decodeResource(getResources(),
				R.drawable.keypad_back);

		bmpDelete = BitmapFactory.decodeResource(getResources(),
				R.drawable.keypad_delete);

		colors = getResources().getIntArray(R.array.rainbow_pattern);
		colorlist = new ArrayList<Integer>();
		for (int i = 0; i < colors.length; i++) {
			colorlist.add(colors[i]);
		}
		// Log.d("Kai", colors.length +"  " + colors[0]);
		mCirclePaints = new ArrayList<Paint>();

		Random r = new Random();
		int conlor;
		int next;
		for (int i = 0; i < POINT_COUNT; i++) {
			next = r.nextInt(colorlist.size());
			conlor = colorlist.get(next);
			colorlist.remove(next);

			// Log.d("Kai", next + " " + conlor + " ");

			// randomColor[i] = conlor;

			mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
			mCirclePaint.setColor(conlor);
			mCirclePaint.setStyle(Style.FILL);
			mCirclePaints.add(mCirclePaint);
		}

		// text
		mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mTextPaint.setColor(mPointColor);
		mTextPaint.setAntiAlias(true);
		mTextPaint.setTextAlign(Paint.Align.CENTER);
		// mTextPaint.setShadowLayer(1.0f, 1.0f, 1.0f, 0x80000000);

		mTextFocusPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mTextFocusPaint.setColor(Color.WHITE);
		mTextFocusPaint.setAntiAlias(true);
		mTextFocusPaint.setTextAlign(Paint.Align.CENTER);

		// center point
		mPointPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mPointPaint.setColor(mPointColor);
		mPointPaint.setStrokeWidth(mCircleWidth);
		mPointPaint.setStyle(Style.STROKE);
		// mPointPaint.setShadowLayer(1.0f, 1.0f, 1.0f, 0x80000000);

		// circle
		mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mCirclePaint.setColor(mCircleColor);
		mCirclePaint.setStrokeWidth(mCircleWidth);
		mCirclePaint.setStyle(Style.FILL);
		// mCirclePaint.setShadowLayer(1.0f, 1.0f, 1.0f, 0x80000000);

		// connection line
		mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mLinePaint.setColor(mLineColor);
		mLinePaint.setStrokeWidth(mLineWidth);
		mLinePaint.setStyle(Style.FILL);
		mLinePaint.setStrokeCap(Cap.ROUND);
		mLinePaint.setStrokeJoin(Join.ROUND);

		// mLinePaint.setShadowLayer(1.0f, 1.0f, 1.0f, 0x80000000);

		// wrong triangle path
		mWrongPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mWrongPaint.setColor(mWrongColor);
		mWrongPaint.setStyle(Style.FILL);

		setPadding(Math.max(getPaddingLeft(), mPaddingView),
				Math.max(getPaddingTop(), mPaddingView),
				Math.max(getPaddingRight(), mPaddingView),
				Math.max(getPaddingBottom(), mPaddingView));

		mWillDrawWrongTriangle = false;

		Log.d("Kai", "Oncreat");
	}

	/**
	 * Set correct PIN String used to check whether the drawn shape is correct
	 * or not.
	 * <p>
	 * You must call this method before begin draw.
	 * </p>
	 * 
	 * @param pin
	 *            the correct PIN String. 0 is index of the first point.
	 *            <b>eg:</b> "012" PIN String represent that the shape connect
	 *            one, two and three points in first row.
	 * @throws IllegalArgumentException
	 *             if parameter <b>pin</b> contains characters besides '0'-'8'
	 *             or same charaters.
	 */
	public void setCorrectPIN(String pin) {
		boolean repeat = false;
		for (int i = 0; i < pin.length() - 1; i++) {
			for (int j = i + 1; j < pin.length(); j++) {
				if (pin.charAt(i) == pin.charAt(j)) {
					repeat = true;
					break;
				}
			}
		}
		boolean match = Pattern.matches("[0-8]{1,9}", pin);
		if (repeat || !match) {
			throw new IllegalArgumentException(
					"The pin must only contains characters '0'-'8' and not be repeat.");
		}
		mCorrectPIN = pin;
	}

	public void setOnDrawListener(OnDrawListener listener) {
		mOnDrawListener = listener;
	}

	private int oldHeigh;

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {

		drawWidth = getWidth() - getPaddingLeft() - getPaddingRight();
		drawHeight = getHeight() - getPaddingTop() - getPaddingBottom();
		oldHeigh = drawHeight;

		if (drawWidth < drawHeight) {
			drawHeight = drawWidth;
		} else {
			drawWidth = drawHeight;
		}

		// setLayoutParams(new
		// LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,drawHeight));

		mPaddingPoint = drawWidth * 0.03f;

		switch (type) {
		case TYPE_1:
			mCircleRadius = (int) ((drawWidth - mPaddingPoint * 12) / 6);
			if (mCircleRadius > 80) {
				mCircleRadius = 80;
				// mPaddingPoint = (drawWidth - mCircleRadius * 6) / 4;
			}
			mTextPaint.setTextSize(mCircleRadius * 2 / 3);
			mTextFocusPaint.setTextSize(mCircleRadius * 2 / 3);

			break;
		case TYPE_2:
			mCircleRadius = (int) ((drawHeight - mPaddingPoint * 6) / 8);

			if (mCircleRadius > 80) {
				mCircleRadius = 80;
				// mPaddingPoint = (drawWidth - mCircleRadius * 6) / 4;
			}
			mTextPaint.setTextSize(mCircleRadius * 4 / 5);
			mTextFocusPaint.setTextSize(mCircleRadius * 4 / 5);
			break;
		}

		// mCircleRadius = (int) ((drawWidth - mPaddingPoint * 10) / 6);

		// mPaddingPoint = drawWidth*0.05f;

		mCircleRadiusKiss = mCircleRadius + mPaddingPoint;

		Log.d("Kai", drawWidth + "   " + drawHeight + "   " + mCircleRadius
				+ "  " + mPaddingPoint);
		computePointsAndWrongTriangleCoordinate();
	}

	/**
	 * Compute the coordinates of 9 center points and wrong triangles.
	 */
	protected void computePointsAndWrongTriangleCoordinate() {

		float baseX = getPaddingLeft()
				+ (drawWidth - (mCircleRadius * 6 + mPaddingPoint * 4)) / 2
				+ mCircleRadius;
		float baseY = getPaddingTop()
				+ (oldHeigh - (mCircleRadius * 8 + mPaddingPoint * 6)) / 2
				+ mCircleRadius;
		float gapX = mPaddingPoint * 2 + mCircleRadius * 2;
		float gapY = mPaddingPoint * 2 + mCircleRadius * 2;

		float r = mCircleRadius;
		int i = 0;
		for (i = 0; i < POINT_COUNT - 1; i++) {
			// compute center point's coordinate
			Point point = new Point();
			point.x = baseX + gapX * (i % 3);
			point.y = baseY + gapY * (i / 3);
			point.index = i + 1;
			mCenterPoints[i + 1] = point;
			// compute wrong triangle path of this point.

		}

		Point point = new Point();
		point.x = baseX + gapX * (1);
		point.y = baseY + gapY * (i / 3);
		point.index = 0;
		mCenterPoints[0] = point;

		point = new Point();
		point.x = baseX + gapX * (0);
		point.y = baseY + gapY * (i / 3);
		point.index = POINT_TYPE_BACK;
		mCenterPoints[POINT_TYPE_BACK] = point;

		point = new Point();
		point.x = baseX + gapX * (2);
		point.y = baseY + gapY * (i / 3);
		point.index = POINT_TYPE_DELETE;
		mCenterPoints[POINT_TYPE_DELETE] = point;

		switch (type) {
		case TYPE_1:
			break;
		case TYPE_2:
			mCircleRadius = mCircleRadius * 4 / 5;
			break;
		}

	}

	@SuppressLint("NewApi")
	@Override
	public boolean onTouchEvent(MotionEvent e) {

		int pointerIndex = e.getActionIndex();

		// get pointer ID
		int pointerId = e.getPointerId(pointerIndex);

		// get masked (not specific to a pointer) action
		int maskedAction = e.getActionMasked();

		switch (maskedAction) {

		case MotionEvent.ACTION_DOWN:
		case MotionEvent.ACTION_POINTER_DOWN: {
			// TODO use data
			if (!isWait) {
				clearDrawn();
				kissSomePoint(e, pointerId);
			}

			kissButton(e, pointerId);
			invalidate();
			break;
		}
		case MotionEvent.ACTION_MOVE: { // a pointer was moved
			// TODO use data
//			if (!isWait) {
//				kissSomePoint(e, pointerId);
//			}
			break;
		}
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_POINTER_UP:
		case MotionEvent.ACTION_CANCEL: {
			// TODO use data
			if (mPointer != null && mPointer.idPointer == pointerId) {

				switch (type) {
				case TYPE_1:

					if (mPointer.indexFocus < 10) {
						mCenterPoints[mPointer.indexFocus].focus = false;
						mCenterPoints[mPointer.indexFocus].drawInc = false;
						mCenterPoints[mPointer.indexFocus].inc = false;
						mCenterPoints[mPointer.indexFocus].touch = false;
						mCenterPoints[mPointer.indexFocus].sizeRadius = 0;

					} else if (mPointer.indexFocus == POINT_TYPE_BACK) {
						mCenterPoints[mPointer.indexFocus].touch = false;
					} else if (mPointer.indexFocus == POINT_TYPE_DELETE) {
						mCenterPoints[mPointer.indexFocus].touch = false;
					}
					break;
				case TYPE_2:
					if (mPointer.indexFocus < 10) {
						mCenterPoints[mPointer.indexFocus].focus = false;
						if (mCenterPoints[mPointer.indexFocus].sizeRadius == mCircleRadius) {

							mCenterPoints[mPointer.indexFocus].drawInc = false;
							mCenterPoints[mPointer.indexFocus].inc = false;
							mCenterPoints[mPointer.indexFocus].touch = false;
							mCenterPoints[mPointer.indexFocus].sizeRadius = 0;
						}
					} else if (mPointer.indexFocus == POINT_TYPE_BACK) {
						mCenterPoints[mPointer.indexFocus].touch = false;
					} else if (mPointer.indexFocus == POINT_TYPE_DELETE) {
						mCenterPoints[mPointer.indexFocus].touch = false;
					}
					break;
				}

				mPointer = null;
			}

			break;
		}
		}
		invalidate();

		return true;
	}

	/**
	 * Clear to status before drawn, there are only 9 points in canvas.
	 */
	protected void clearDrawn() {

		mDrawnPoints.clear();
		mLastDrawnPoint = null;
		mCirclePaint.setColor(mCircleColor);
		mWillDrawWrongTriangle = false;
		// for (int i = 0; i < POINT_COUNT; i++) {
		// mCenterPoints[i].sizeRadius = 0;
		//
		// }
	}

	/**
	 * Check whether finger has entered some point's area or not.
	 * 
	 * @param e
	 *            motion envent.
	 */
	protected boolean kissSomePoint(MotionEvent e, int pointerId) {
		// We just check the one point.
		if (mPointer != null)
			return false;
		try {
			mCurrX = e.getX(pointerId);
			mCurrY = e.getY(pointerId);

			for (int i = 0; i < POINT_COUNT; i++) {
				Point p = mCenterPoints[i];
				if (Math.sqrt(Math.pow(mCurrX - p.x, 2)
						+ Math.pow(mCurrY - p.y, 2)) <= mCircleRadiusKiss) {

					if (p.index < 10) {
						p.focus = true;
						p.touch = true;
						p.drawInc = true;
						p.inc = true;
						mPointer = new Pointer(pointerId, i);

						mOnDrawListener.onValueSelected(this, p.index);
					} else if (p.index == POINT_TYPE_BACK && !p.touch) {
						p.touch = true;
						mPointer = new Pointer(pointerId, i);
						mOnDrawListener.onBacked(this);
					} else if (p.index == POINT_TYPE_DELETE && !p.touch) {
						mOnDrawListener.onDelete(this);
						p.touch = true;
						mPointer = new Pointer(pointerId, i);
					}

				}
			}

		} catch (Exception ex) {
			return true;
		}
		return true;
	}

	protected boolean kissButton(MotionEvent e, int pointerId) {
		// We just check the one point.
		if (mPointer != null)
			return false;
		try {
			mCurrX = e.getX(pointerId);
			mCurrY = e.getY(pointerId);

			for (int i = POINT_TYPE_BACK; i < POINT_COUNT; i++) {
				Point p = mCenterPoints[i];
				if (Math.sqrt(Math.pow(mCurrX - p.x, 2)
						+ Math.pow(mCurrY - p.y, 2)) <= mCircleRadiusKiss) {

					if (p.index == POINT_TYPE_BACK && !p.touch) {
						p.touch = true;
						mPointer = new Pointer(pointerId, i);
						mOnDrawListener.onBacked(this);
					} else if (p.index == POINT_TYPE_DELETE && !p.touch) {
						mOnDrawListener.onDelete(this);
						p.touch = true;
						mPointer = new Pointer(pointerId, i);
					}

				}
			}

		} catch (Exception ex) {
			return true;
		}
		return true;
	}

	private boolean isCornerPoint(Point p) {
		if (p.index == 0 || p.index == 2 || p.index == 6 || p.index == 8) {
			return true;
		} else {
			return false;
		}
	}

	protected void onDrawStart() {
		if (mOnDrawListener != null) {
			mOnDrawListener.onDrawStart(this);
		} else {
			Log.w(TAG,
					"You should call NinePINView.setOnDrawCompleteListener() method to set a draw listener.");
		}
	}

	protected void onDrawComplete(boolean correct) {
		// XXX: this is not required. The correct PIN should be set by user.
		if (mCurrMode == Mode.MODE_STUDY) {
			mCorrectPIN = mDrawnPIN;
		}

		if (mOnDrawListener != null) {
			mOnDrawListener.onDrawComplete(this, correct);
		} else {
			Log.w(TAG,
					"You should call NinePINView.setOnDrawCompleteListener() method to set a draw listener.");
		}
	}

	@Override
	protected void onDraw(Canvas canvas) {
		// super.onDraw(canvas);

		switch (type) {
		case TYPE_1:

			for (int i = 0; i < POINT_COUNT; i++) {
				Point p = mCenterPoints[i];

				if (p.index < 10) {
					if (!p.focus) {

						canvas.drawCircle(p.x, p.y, mCircleRadius, mPointPaint);
						Rect bounds = new Rect();
						mTextPaint.getTextBounds(p.index + "", 0, 1, bounds);
						canvas.drawText(p.index + "", p.x,
								p.y + bounds.height() / 2, mTextPaint);

					} else {

						canvas.drawCircle(p.x, p.y, mCircleRadius, mCirclePaint);
						Rect bounds = new Rect();
						mTextFocusPaint.getTextBounds(p.index + "", 0, 1,
								bounds);
						canvas.drawText(p.index + "", p.x,
								p.y + bounds.height() / 2, mTextFocusPaint);
					}
				} else if (p.index == POINT_TYPE_BACK) {
					canvas.drawBitmap(bmpBack, p.x - bmpBack.getWidth() / 2,
							p.y - bmpBack.getHeight() / 2, null);
				} else if (p.index == POINT_TYPE_DELETE) {
					canvas.drawBitmap(bmpDelete,
							p.x - bmpDelete.getWidth() / 2,
							p.y - bmpDelete.getHeight() / 2, null);
				}

			}

			break;
		case TYPE_2:
			for (int i = 0; i < POINT_COUNT; i++) {
				Point p = mCenterPoints[i];

				if (p.index < 10) {
					if (!p.focus) {

						if (p.touch) {

							if (p.drawInc) {
								if (p.inc) {

									if (p.sizeRadius < mCircleRadius + 10) {

										p.sizeRadius += 4;
									} else {
										p.inc = false;
									}
								} else {
									p.sizeRadius -= 5;
									if (p.sizeRadius < mCircleRadius - 10) {
										Log.d("Kai", "xong");
										// p.sizeRadius = mCircleRadius;
										p.focus = false;
										p.touch = false;
										p.drawInc = false;
										p.inc = false;
										p.sizeRadius = 0;
									}

								}

							}

							canvas.drawCircle(p.x, p.y, p.sizeRadius,
									mCirclePaints.get(i));
							Rect bounds = new Rect();
							mTextFocusPaint.getTextBounds(p.index + "", 0, 1,
									bounds);
							canvas.drawText(p.index + "", p.x,
									p.y + bounds.height() / 2, mTextFocusPaint);
						} else {

							Rect bounds = new Rect();
							mTextPaint
									.getTextBounds(p.index + "", 0, 1, bounds);
							canvas.drawText(p.index + "", p.x,
									p.y + bounds.height() / 2, mTextPaint);
						}

					} else {

						if (p.drawInc) {
							if (p.inc) {
								if (p.sizeRadius < mCircleRadius + 10) {
									p.sizeRadius += 5;
								} else {
									p.inc = false;
								}
							} else {
								p.sizeRadius -= 5;
								if (p.sizeRadius < mCircleRadius) {
									p.sizeRadius = mCircleRadius;
									p.drawInc = false;
								}

							}
						}

						canvas.drawCircle(p.x, p.y, p.sizeRadius,
								mCirclePaints.get(i));
						Rect bounds = new Rect();
						mTextFocusPaint.getTextBounds(p.index + "", 0, 1,
								bounds);
						canvas.drawText(p.index + "", p.x,
								p.y + bounds.height() / 2, mTextFocusPaint);
					}
				} else if (p.index == POINT_TYPE_BACK) {
					canvas.drawBitmap(bmpBack, p.x - bmpBack.getWidth() / 2,
							p.y - bmpBack.getHeight() / 2, null);
				} else if (p.index == POINT_TYPE_DELETE) {
					canvas.drawBitmap(bmpDelete,
							p.x - bmpDelete.getWidth() / 2,
							p.y - bmpDelete.getHeight() / 2, null);
				}

			}
			break;
		}

		invalidate();
		super.onDraw(canvas);
	}

	/**
	 * Interface definition for a callback to be invoked when finger drawn is
	 * complete.
	 */
	public interface OnDrawListener {

		/**
		 * Called when finger begin to draw.
		 * 
		 * @param ninePINView
		 *            The ninePINView which is being drawing.
		 */
		public void onDrawStart(PasscodeView passcodeView);

		public void onValueSelected(PasscodeView passcodeView, int value);

		/**
		 * Called when finger draw has been complete.
		 * 
		 * @param ninePINView
		 *            The ninePINView has been drawn.
		 * @param correct
		 *            true if shape that has been drawn is correct, false if
		 *            wrong.
		 */
		public void onDrawComplete(PasscodeView passcodeView, boolean correct);

		public void onBacked(PasscodeView passcodeView);

		public void onDelete(PasscodeView passcodeView);

	}

	public int getPointColor() {
		return mPointColor;
	}

	public void setPointColor(int color) {
		mPointColor = color;
		mPointPaint.setColor(color);
	}

	public void setCircleColor(int color) {
		mCircleColor = color;
		mCirclePaint.setColor(color);
	}

	public void setLineColor(int color) {
		mLineColor = color;
		mLinePaint.setColor(color);
	}

	public void setPointSize(int size) {
		mPointSize = size;
		mPointPaint.setStrokeWidth(size);
	}

	public void setCircleWidth(int width) {
		mCircleWidth = width;
		mCirclePaint.setStrokeWidth(width);
	}

	// public void setCircleRadius(int raduis) {
	// mCircleRadius = raduis;
	// mCirclePaint.setStrokeWidth(raduis);
	// }

	public void setLineWidth(int width) {
		mLineWidth = width;
		mLinePaint.setStrokeWidth(width);
	}

	/**
	 * Set current work mode of NinePINView.
	 * 
	 * @param mode
	 *            {@link Mode#MODE_STUDY} or {@link Mode#MODE_WORK}
	 */
	public void setMode(Mode mode) {
		mCurrMode = mode;
	}

	/**
	 * Get the current work mode of NinePINView.
	 * 
	 * @return
	 */
	public Mode getMode() {
		return mCurrMode;
	}

	/**
	 * 
	 * @return PIN String has been drawn.
	 */
	public String getDrawnPIN() {
		return mDrawnPIN;
	}

	public boolean isWait() {
		return isWait;
	}

	public void setWait(boolean isWait) {
		this.isWait = isWait;
	}

	public int getType() {
		return type;
	}

	public void setType(int type) {
		this.type = type;
	}

	@Override
	protected void onDetachedFromWindow() {
		// TODO Auto-generated method stub
		super.onDetachedFromWindow();
		if (bmpBack != null) {
			bmpBack.recycle();
			bmpBack = null;
		}

		if (bmpDelete != null) {
			bmpDelete.recycle();
			bmpDelete = null;
		}
	}

}
